/*
 Basic ESP8266 MQTT example
 This sketch demonstrates the capabilities of the pubsub library in combination
 with the ESP8266 board/library.
 It connects to an MQTT server then:
  - publishes "hello world" to the topic "outTopic" every two seconds
  - subscribes to the topic "inTopic", printing out any messages
    it receives. NB - it assumes the received payloads are strings not binary
  - If the first character of the topic "inTopic" is an 1, switch ON the ESP Led,
    else switch it off
 It will reconnect to the server if the connection is lost using a blocking
 reconnect function. See the 'mqtt_reconnect_nonblocking' example for how to
 achieve the same result without blocking the main loop.
 To install the ESP8266 board, (using Arduino 1.6.4+):
  - Add the following 3rd party board manager under "File -> Preferences -> Additional Boards Manager URLs":
       http://arduino.esp8266.com/stable/package_esp8266com_index.json
  - Open the "Tools -> Board -> Board Manager" and click install for the ESP8266"
  - Select your ESP8266 in "Tools -> Board"
*/
#include <Arduino.h>
#include <EEPROM.h>
#include <Ticker.h>
#include <WiFiClient.h>
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClientSecureBearSSL.h>
#include <SoftwareSerial.h>

SoftwareSerial softSerial(4, 5); // RX=GPIO4, TX=GPIO5
WiFiClient wifi_client;
PubSubClient mqtt_client(wifi_client);
ESP8266WebServer web_server(80);

#define EEPROM_WIFI_SSID_MODIFF   45
#define EEPROM_WIFI_SSID 59
#define EEPROM_WIFI_PASS   91
#define EEPROM_MQTT_WEB_SERVER_IP   155
#define EEPROM_MQTT_CLIENT_ID   179
#define EEPROM_MQTT_USER 203
#define EEPROM_MQTT_PASS   267
#define EEPROM_MQTT_TOPICP   291
#define EEPROM_MQTT_TOPICS   315

String wifi_ssid = "",wifi_password = "",web_mqtt_server = "",mqtt_client_id = "",mqtt_user = "",mqtt_pass = "",mqtt_topicp = "",mqtt_topics = "";
const uint8_t fingerprint[20] = {0xB0, 0xB1, 0x5C, 0x25, 0x3F, 0xAB, 0xA3, 0xC3, 0xE9, 0xA1, 0xC0, 0x70, 0x30, 0x54, 0x5F, 0xF8, 0x9A, 0xEB, 0xAC, 0x4B};
/*网页代码*/
/**
<style>\
      body { background-color: #FFFFFF; font-family: Arial, Helvetica, Sans-Serif; Color: #1E90FF; }\
    </style>\ style=\"margin-top:0px;margin-bottom: 0px;\" style=\"margin-top:0px;font-style:italic;font-size:14px;text-align:center;color:#EE9A00\"
**/
const String html_s = "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\"><title></title></head><body>";
const String html_e = "<script type=\"text/javascript\">function a(){console.log('b');}</script></body></html>";
const String form_s = "<form action=";
const String form_e ="</form>";
const String index_link = "<a href=\"/\">index</a><br>";
const String html_index = "<center>\
<a href=\"chgGifiIfo\">wifi info</a><br>\
<a href=\"chgServerIP\">server ip</a><br>\
<a href=\"chgMqttInfo\">mqtt info</a><br>\
<a href=\"httpsRqst\">https request</a><br>\
<a href=\"mqttPublish\">mqtt publish</a></center><br>";
const String html_chgwifiifo = index_link + "<input type=\"text\" name=\"ws\" required placeholder=\"ssid\"><input type=\"text\" name=\"pwd\" required placeholder=\"pwd\"><input type=\"submit\" value=\"wifi info\">";
const String html_chg_server_ip = index_link + "<input type=\"text\" name=\"si\" required placeholder=\"mqtt and web server ip\"><input type=\"submit\" value=\"server ip\">";
const String html_mqtt_info = index_link + "\
<input type=\"text\" name=\"mi\" required placeholder=\"mqtt id\">\
<input type=\"text\" name=\"mn\" required placeholder=\"mqtt user\">\
<input type=\"text\" name=\"mpwd\" required placeholder=\"mqtt password\">\
<input type=\"text\" name=\"mptp\" required placeholder=\"mqtt P topip\">\
<input type=\"text\" name=\"mstc\" required placeholder=\"mqtt S topic\">\
<input type=\"submit\" value=\"mqtt info\">";
const String html_https_rqst = index_link + "<input type=\"text\" name=\"hrt\" required placeholder=\"request body\"><input type=\"submit\" value=\"https request\">";
const String html_mqtt_publish = index_link + "<input type=\"text\" name=\"mpsh\" required placeholder=\"publish content\"><input type=\"submit\" value=\"mqtt publish\">";
/*保存数据到eeprom,addr是字符串的地址，str为要保存的字符串,不同数据以\0结尾，度取数据时，遇\0结束读取。数据中不允许有\0*/
int writeToEeprom(int addr,String str){
  //  if(-1 != str.indexOf("\0"))return 1;//数据中不允许有\0
  int i = 0;
  int str_len = str.length();
  for (; i < str_len; i++){
    EEPROM.write(addr + i, str[i]);
  }
  EEPROM.write(addr + i, '\0');
  EEPROM.commit();
  return 0;
}
/*从eeprom中读取数据，addr是起始位(字符串首地址)，遇\0时结束读取*/
String readFromEeprom(int addr){ 
  String data = "";
  char tem = 'c';
  int i = 0;
  while(1){
    tem = char(EEPROM.read(addr + i++));
    data += tem;
    if('\0' == tem)break;
  }
  return data;
}
/*https请求*/
int httpsReqst(){
  //  if ((WiFiMulti.run() == WL_CONNECTED)) {  // wait for WiFi connection
    std::unique_ptr<BearSSL::WiFiClientSecure>client(new BearSSL::WiFiClientSecure);
    client->setFingerprint(fingerprint);// Or, if you happy to ignore the SSL certificate, then use the following line instead:
    // client->setInsecure();
    HTTPClient https;
    Serial.print("[HTTPS] begin...\r\n");
    if (https.begin(*client, "https://www.notion666.com/wishc/makeAwish")) {  // HTTPS
      Serial.print("[HTTPS] GET...\r\n");
      int httpCode = https.GET();// start connection and send HTTP header，httpCode will be negative on error
      Serial.printf("httpCode:%d\r\n",httpCode);
      if (httpCode > 0) {// HTTP header has been send and Server response header has been handled
        Serial.printf("[HTTPS] GET... code: %d\r\n", httpCode);
        if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {// file found at server
          String payload = https.getString();
          Serial.println(payload);
        }
      }else{
        Serial.printf("[HTTPS] GET... failed, error: %s\r\n", https.errorToString(httpCode).c_str());
      }
      https.end();
    }else{
      Serial.printf("[HTTPS] Unable to connect\r\n");
    }
  //  }
  //  Serial.println("Wait 10s before next round...");
  //  delay(10000);
  return 0;
}
/*默认页面的处理函数*/
void webServerInex() {
  web_server.send(200, "text/html", html_s+html_index+html_e);//把页面发送给终端
}
void chgGifiIfo() {
  writeToEeprom(EEPROM_WIFI_SSID,web_server.arg("ws"));
  writeToEeprom(EEPROM_WIFI_PASS,web_server.arg("wn"));
  writeToEeprom(EEPROM_WIFI_SSID_MODIFF,"acacacac");
  web_server.send(200, "text/html", html_s+form_s+"\"chgGifiIfo\">"+html_chgwifiifo+form_e+html_e);//把页面发送给终端
}
void chgServerIP() {
  writeToEeprom(EEPROM_MQTT_WEB_SERVER_IP,web_server.arg("si"));
  web_server.send(200, "text/html", html_s+form_s+"\"chgServerIP\">"+html_chg_server_ip+form_e+html_e);//把页面发送给终端
}
void chgMqttInfo() {
  writeToEeprom(EEPROM_MQTT_CLIENT_ID,web_server.arg("mi"));
  writeToEeprom(EEPROM_MQTT_USER,web_server.arg("mn"));
  writeToEeprom(EEPROM_MQTT_PASS,web_server.arg("mpwd"));
  writeToEeprom(EEPROM_MQTT_TOPICP,web_server.arg("mptp"));
  writeToEeprom(EEPROM_MQTT_TOPICS,web_server.arg("mstc"));
  web_server.send(200, "text/html", html_s+form_s+"\"chgMqttInfo\">"+html_mqtt_info+form_e+html_e);//把页面发送给终端
}
void httpsRqst() {
  httpsReqst();
  web_server.send(200, "text/html", html_s+form_s+"\"httpsRqst\">"+html_https_rqst+form_e+html_e);//把页面发送给终端
}
void mqttPublish() {
  mqtt_client.publish(mqtt_topicp.c_str(),(web_server.arg("mqtt_publish")).c_str());
  web_server.send(200, "text/html", html_s+form_s+"\"mqttPublish\">"+html_mqtt_publish+form_e+html_e);//把页面发送给终端
}

void relayToSTM32F103ZET6() {//接收http请求并将信息通过串口转发给STM32F103ZET6
  //String arg_name = web_server.argName(0);
  softSerial.println(web_server.arg("ops"));
}

void handleNotFound() {
  String message = "File Not Found\n\n";
  message += "URI: ";
  message += web_server.uri();
  message += "\nMethod: ";
  message += (web_server.method() == HTTP_GET) ? "GET" : "POST";
  message += "\nArguments: ";
  message += web_server.args();
  message += "\n";
  for (uint8_t i = 0; i < web_server.args(); i++) {
    message += " " + web_server.argName(i) + ": " + web_server.arg(i) + "\n";
  }
  web_server.send(404, "text/plain", message);
}
void setup_wifi() {
  delay(10);
  Serial.println();
  Serial.print("Connecting to ");
  //Serial.println(wifi_ssid);
  WiFi.mode(WIFI_STA);
  //String wifi_ssid_pwd_modiff_flag = "";
  //for(int i=0;i<8;){
    //wifi_ssid_pwd_modiff_flag += char(EEPROM.read(EEPROM_WIFI_SSID_MODIFF + i++));
  //}
  WiFi.begin("adol-3447C6", "12345678");Serial.println("default wifi ssid_passwd");
  //if(0 == wifi_ssid_pwd_modiff_flag.indexOf("acacacac")){
  //  WiFi.begin(wifi_ssid, wifi_password);//连接wifi
  //  Serial.println("new wifi ssid_passwd");
  //}else{WiFi.begin("ac", "cbCB1234");Serial.println("default wifi ssid_passwd");}
  while (WiFi.status() != WL_CONNECTED) {// Wait for connection
    delay(500);
    Serial.print(".");
  }

  randomSeed(micros());

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void mqttCallback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();
  // Switch on the LED if an 1 was received as first character
  if ((char)payload[0] == '1') {
    digitalWrite(BUILTIN_LED, LOW);   // Turn the LED on (Note that LOW is the voltage level
    // but actually the LED is on; this is because
    // it is active low on the ESP-01)
  } else {
    digitalWrite(BUILTIN_LED, HIGH);  // Turn the LED off by making the voltage HIGH
  }

}
void mqttRecvMsg(){}
void reconnect() {
  while (!mqtt_client.connected()) {// Loop until we're reconnected
    Serial.print("Attempting MQTT connection...");
    if (mqtt_client.connect(mqtt_client_id.c_str())) {// Attempt to connect
      Serial.println("connected");
      mqtt_client.publish(mqtt_topicp.c_str(), "hello world");// Once connected, publish an announcement...
      mqtt_client.subscribe(mqtt_topics.c_str());// ... and resubscribe
    } else {
      Serial.print("failed, rc=");
      Serial.print(mqtt_client.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);// Wait 5 seconds before retrying
    }
  }
}

void setup() {
  Serial.begin(115200);
  //SoftwareSerial softSerial(4, 5); // RX=GPIO4, TX=GPIO5
  softSerial.begin(115200);
  softSerial.println("From software serial");
  pinMode(LED_BUILTIN,OUTPUT);//设置IO口2为输出接口，Arduino 上用到的I/O 口都要进行类似这样的定义。
  //EEPROM.begin(1024);
  //wifi_ssid = readFromEeprom(EEPROM_WIFI_SSID);
  //wifi_password = readFromEeprom(EEPROM_WIFI_PASS);
  //mqtt_client_id = readFromEeprom(EEPROM_MQTT_CLIENT_ID);
 // mqtt_user = readFromEeprom(EEPROM_MQTT_USER);
  //mqtt_pass = readFromEeprom(EEPROM_MQTT_PASS);
  //mqtt_topicp = readFromEeprom(EEPROM_MQTT_TOPICP);
  //mqtt_topics = readFromEeprom(EEPROM_MQTT_TOPICS);
  //web_mqtt_server = readFromEeprom(EEPROM_MQTT_WEB_SERVER_IP);
  //Serial.println();Serial.println(wifi_ssid);Serial.println(wifi_password);
  //Serial.println(mqtt_client_id);Serial.println(mqtt_user);Serial.println(mqtt_pass);Serial.println(mqtt_topicp);Serial.println(mqtt_topics);
  setup_wifi();
  web_server.on("/", webServerInex);//配置web服务默认页面的处理函数
  web_server.on("/chgGifiIfo", chgGifiIfo);
  web_server.on("/chgServerIP", chgGifiIfo);
  web_server.on("/chgMqttInfo", chgGifiIfo);
  web_server.on("/httpsRqst", chgGifiIfo);
  web_server.on("/mqttPublish", chgGifiIfo);
  web_server.on("/relayToSTM32F103ZET6", relayToSTM32F103ZET6);
  web_server.onNotFound(handleNotFound);
  web_server.begin();//开启web服务
  Serial.println("\r\nHTTP server started");
  //mqtt_client.setServer(&web_mqtt_server[0], 1883);// 配置MQTT服务器
  //mqtt_client.setCallback(mqttCallback);// 设置回调函数
  //mqtt_client.setKeepAlive(60);
}

void loop() {
  //if (!mqtt_client.connected()) {
  //  reconnect();
  //}
  Serial.println("134220973|B5|5_134221481|B5_134220757|5000_134221273|B5\r\n");
  softSerial.println("134220973|B5|5_134221481|B5_134220757|5000_134221273|B5\r\n");
  digitalWrite(LED_BUILTIN,HIGH);//IO口2设置为高电平，点亮数字2口LED
  delay(500);//延时500mS
  digitalWrite(LED_BUILTIN,LOW);//IO口2设置为低电平，熄灭数字2口LED
  delay(500);//延时500mS
  web_server.handleClient();
  mqtt_client.loop();
}
